class Compile {
    constructor(el, vm) {
        // 获取宿主节点
        this.$el = document.querySelector(el)
        this.$vm = vm

        //compile
        if (this.$el) {
            // change dom to fragment
            this.$fragment = this.nodeToFragment(this.$el)

            // run compile
            this.compile(this.$fragment)

            // append fragment to node
            this.$el.appendChild(this.$fragment)
        }
    }

    nodeToFragment(el) {
        const frag = document.createDocumentFragment()
        
        //move node doms to frag
        let child
        while (child = el.firstChild) {
            frag.appendChild(child)
        }

        return frag
    }

    isElement(el) {
        return el.nodeType === 1
    }

    isInterpolation(el) {
        return el.nodeType === 3 && /\{\{(.*)\}\}/.test(el.textContent)
    }

    compileText(el) {
        console.log(RegExp.$1)
        // el.textContent = this.$vm.$data[RegExp.$1]
        this.update(el, this.$vm, RegExp.$1, 'text')
    }

    update(node, vm, exp, dir) {
        const updateFun = this[dir+'Updater']
        // 初始化
        updateFun && updateFun(node, vm.$data[exp])
        // 依赖收集
        new Watcher(vm, exp, function(value) {
            updateFun(node, value)
        })
    }

    model(node, vm, exp) {
        this.update(node, vm, exp, 'model')

        node.addEventListener('input', e => {
            vm[exp] = e.target.value
        })
    }

    modelUpdater(node, val) {
        node.value = val
    }

    text(node, vm, exp) {
        this.update(node, vm, exp, 'text')
    }

    textUpdater(node, val) {
        node.textContent = val
    }

    isDirective(command) {
        return command.indexOf('k-') == 0
    }

    isEvent(command) {
        return command.indexOf('@') == 0
    }

    isForloop(command) {
        return command.indexOf('k-for') === 0
    }

    eventHandler(node, vm, exp, e) {
        const fn = vm.$options.methods && vm.$options.methods[exp]
        if (e && fn) {
            node.addEventListener(e, fn.bind(vm))
        }
    }

    compile(el) {
        const nodes = el.childNodes
        Array.from(nodes).forEach(node => {
            if (this.isElement(node)) {
                const nodeName = node.nodeName
                const attrs = node.attributes
                Array.from(attrs).forEach(attr => {
                    const attName = attr.name
                    const exp = attr.value
                    if (this.isForloop(attName)) {
                        // const {item, index, data} = /\((*),(*)in(*)\)/
                        // const model = String(exp.split('in')[-1]).trim()
                        console.log(exp)
                    }
                    else if (this.isDirective(attName)) {
                        // k-text
                        const dir = attName.substring(2)
                        // run
                        this[dir] && this[dir](node, this.$vm, exp)
                    }
                    else if (this.isEvent(attName)) {
                        // @click
                        const e = attName.substring(1)
                        // run
                        this.eventHandler(node, this.$vm, exp, e)
                    }
                })
            }
            else if (this.isInterpolation(node)) {
                this.compileText(node)
            }
            
            // 递归子节点
            if (node.childNodes && node.childNodes.length > 0) {
                this.compile(node)
            }
        })
    }
}